package com.zsc.common.web.util;

import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpRequest;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.apache.http.ssl.SSLContextBuilder;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.UnknownHostException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

/**
 * Created by xbkaishui on 17/3/11.
 */
public class HttpClientHolder {

    private static CloseableHttpClient httpClient;

    /**
     *
     */
    private HttpClientHolder() {
    }

    /**
     * @return
     */
    public static synchronized CloseableHttpClient getHttpClient() {
        if (null == httpClient) {
            HttpRequestRetryHandler myRetryHandler = new HttpRequestRetryHandler() {
                /**
                 *
                 * @see HttpRequestRetryHandler#retryRequest(IOException, int, HttpContext)
                 */
                @Override
                public boolean retryRequest(IOException exception, int executionCount,
                                            HttpContext context) {
                    if (executionCount >= 3) {
                        // Do not retry if over max retry count
                        return false;
                    }
                    if (exception instanceof InterruptedIOException) {
                        // Timeout
                        return false;
                    }
                    if (exception instanceof UnknownHostException) {
                        // Unknown host
                        return false;
                    }
                    if (exception instanceof ConnectTimeoutException) {
                        // Connection refused
                        return false;
                    }
                    if (exception instanceof SSLException) {
                        // SSL handshake exception
                        return false;
                    }

                    HttpClientContext clientContext = HttpClientContext.adapt(context);
                    HttpRequest request = clientContext.getRequest();
                    boolean idempotent = !(request instanceof HttpEntityEnclosingRequest);
                    if (idempotent) {
                        // Retry if the request is considered idempotent
                        return true;
                    }
                    return false;
                }

            };
            try {
                //add https support
                SSLContext sslContext = new SSLContextBuilder()
                        .loadTrustMaterial(null, new TrustStrategy() {
                            @Override
                            public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                                return true;
                            }
                        }).build();

                //配置请求的超时设置
                RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(3000)
                        .setConnectTimeout(6000).setSocketTimeout(10000).build();
                PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager();
                cm.setDefaultMaxPerRoute(300);//对每个指定连接的服务器（指定的ip）可以创建并发300 socket进行访问
                cm.setMaxTotal(2000);//创建socket的上线是2000
                cm.closeIdleConnections(5, TimeUnit.MINUTES);

                httpClient = HttpClients.custom().setRetryHandler(myRetryHandler)
                        .setSslcontext(sslContext)
                        .setSSLHostnameVerifier(new NoopHostnameVerifier())
                        .setDefaultRequestConfig(requestConfig).setConnectionManager(cm).build();
            } catch (Exception e) {
                throw  new RuntimeException(e);
            }
        }
        return httpClient;
    }
}
